//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_dao

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"errors"
	"strings"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"github.com/dchest/uniuri"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var WrongPasswdErr = errors.New("wrong password")

type UserPasswdDbItem struct {
	UserId    string `bson:"_id"`
	Salt      string `bson:"salt"`
	EncPasswd string `bson:"encPasswd"`
}

type _UserPasswdDao struct {
	mc *mongo.Collection
}

func newUserPasswdDao(db *mongo.Database) (*_UserPasswdDao, error) {
	mc := db.Collection(db_ns.DB_NS_USER + "passwd")
	return &_UserPasswdDao{mc: mc}, nil
}

func (db *_UserPasswdDao) Set(ctx context.Context, userId, passwd string) error {
	salt := uniuri.NewLen(16)
	encPasswd := db.encPasswd(salt, passwd)
	dbItem := &UserPasswdDbItem{
		UserId:    userId,
		Salt:      salt,
		EncPasswd: encPasswd,
	}
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": userId}, bson.M{"$set": dbItem}, options.Update().SetUpsert(true))
	return err
}

func (db *_UserPasswdDao) encPasswd(salt, passwd string) string {
	h := md5.New()
	h.Write([]byte(salt))
	h.Write([]byte(passwd))
	retStr := hex.EncodeToString(h.Sum(nil))
	return strings.ToLower(retStr)
}

func (db *_UserPasswdDao) Auth(ctx context.Context, userId, passwd string) error {
	dbItem := UserPasswdDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": userId}).Decode(&dbItem)
	if err != nil {
		return err
	}
	encPasswd := db.encPasswd(dbItem.Salt, passwd)
	if encPasswd != dbItem.EncPasswd {
		return WrongPasswdErr
	}
	return nil
}

func (db *_UserPasswdDao) ChangePasswd(ctx context.Context, userId, oldPasswd, newPasswd string) error {
	err := db.Auth(ctx, userId, oldPasswd)
	if err != nil {
		return err
	}
	err = db.Set(ctx, userId, newPasswd)
	if err != nil {
		return err
	}
	return nil
}
